package io.cattle.platform.process.common.spring; import io.cattle.platform.engine.process.impl.ResourceStatesDefinition; import io.cattle.platform.process.common.generic.GenericResourceProcessDefinition; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Element; public class ProcessParser implements BeanDefinitionParser { private static AtomicInteger COUNTER = new AtomicInteger(); @Override public BeanDefinition parse(Element element, ParserContext parserContext) { String id = element.getAttribute("id"); String name = element.getAttribute("name"); String start = element.getAttribute("start"); String transitioning = element.getAttribute("transitioning"); String stateField = element.getAttribute("stateField"); String done = element.getAttribute("done"); String delegate = element.getAttribute("delegate"); String resourceType = element.getAttribute("resourceType"); if (StringUtils.isBlank(delegate)) { delegate = null; } return parse(id, stateField, name, start, transitioning, done, resourceType, delegate, new HashMap<String, String>(), parserContext); } protected BeanDefinition parse(String id, String stateField, String name, String start, String transitioning, String done, String resourceType, String delegate, Map<String, String> renames, ParserContext parserContext) { if (StringUtils.isBlank(id)) { if (StringUtils.isBlank(name)) { id = "generated$" + GenericResourceProcessDefinition.class.getSimpleName() + "$" + COUNTER.incrementAndGet(); } else { id = "generated$" + name; } } BeanDefinitionBuilder statesBuilder = BeanDefinitionBuilder.genericBeanDefinition(ResourceStatesDefinition.class); if (!StringUtils.isBlank(stateField)) { statesBuilder.addPropertyValue("stateField", stateField); } statesBuilder.addPropertyValue("startStates", getSet(start, renames)); statesBuilder.addPropertyValue("transitioningStatesMap", getMap(transitioning, renames)); statesBuilder.addPropertyValue("doneStatesMap", getMap(done, renames)); String childId = parserContext.getReaderContext().generateBeanName(statesBuilder.getBeanDefinition()); BeanDefinitionBuilder processDefBuilder = BeanDefinitionBuilder.genericBeanDefinition(GenericResourceProcessDefinition.class); processDefBuilder.addPropertyValue("name", name); processDefBuilder.addPropertyValue("resourceType", resourceType); processDefBuilder.addPropertyValue("processDelegateName", delegate); processDefBuilder.addPropertyReference("statesDefinition", childId); register(childId, statesBuilder, parserContext); return register(id, processDefBuilder, parserContext); } protected BeanDefinition register(String id, BeanDefinitionBuilder builder, ParserContext parserContext) { BeanDefinition def = builder.getBeanDefinition(); BeanDefinitionHolder holder = new BeanDefinitionHolder(def, id); BeanDefinitionReaderUtils.registerBeanDefinition(holder, parserContext.getRegistry()); return def; } protected Set<String> getSet(String values, Map<String, String> renames) { if (StringUtils.isBlank(values)) { return Collections.emptySet(); } Set<String> result = new LinkedHashSet<String>(); for (String value : values.trim().split("\\s*,\\s*")) { String translated = renames.get(value); result.add(translated == null ? value : translated); } return result; } protected Map<String, String> getMap(String values, Map<String, String> renames) { if (StringUtils.isBlank(values)) { return Collections.emptyMap(); } Map<String, String> result = new LinkedHashMap<String, String>(); if (values.indexOf("=") == -1 && values.indexOf(",") == -1) { result.put(null, values.trim()); } else { for (String value : values.trim().split("\\s*,\\s*")) { if (value.indexOf('=') == -1) { throw new IllegalArgumentException("Setting must be a single value or a list of key/values in the form from1=to1,from2=to2"); } else { String[] parts = value.split("="); result.put(parts[0], parts[1]); } } } return translate(result, renames); } protected Map<String, String> translate(Map<String, String> values, Map<String, String> renames) { Map<String, String> result = new LinkedHashMap<String, String>(); for (Map.Entry<String, String> entry : values.entrySet()) { String key = renames.get(entry.getKey()); String value = renames.get(entry.getValue()); result.put((key == null ? entry.getKey() : key), (value == null ? entry.getValue() : value)); } return result; } }